#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <string.h>

#include <sys/types.h>

#include "dbm.h"

typedef struct block {
	u_int32_t record_count;
	u_int32_t last_record;
} db_block_t;

typedef struct _db_cache {
	u_int32_t free_size;
	char *mem;
} db_cache_t;

typedef struct _db_hdr {
	size_t record_size;
} db_hdr_t;

typedef struct _db {
	int fd;
	db_cache_t *cache;
	db_hdr_t *db_hdr;
	db_block_t *blk;
} db_t;

typedef struct _db_env {
	int tmp;
} db_env_t;

typedef struct _db_txn {
	int tmp;
} db_txn_t;

typedef struct _db_type {
	int tmp;
} db_type_t;

typedef struct _dbt {
	void *data;
	size_t size;
} dbt_t;

#define	db_mutex_lock(db)
#define	db_mutex_unlock(db)

db_cache_t * db_cache_create(db_t *db, size_t cache_size)
{
	db_cache_t *cache;

	__param_check_and_return(db == NULL, -EINVAL, NULL);

	cache = malloc(cache_size);
	if (!cache) {
		errno = -ENOMEM;
		return NULL;
	}

	return cache;
}

int db_create(db_t **dbp, db_env_t *dbenv, u_int32_t flags)
{
	int ret;
	db_t *db = NULL;

	db = malloc(sizeof(db_t));
	if (!db)
		return -ENOMEM;

	*dbp = db;
	return 0;
}

int db_open(db_t *db, db_txn_t *txnid, const char *file,
	    const char *database, db_type_t type, u_int32_t flags, int mode)
{
	int ret;

	if (!db || !database)
		return -EINVAL;

	db->fd = open(database, O_RDWR | O_CREAT);
	if (db->fd < 0) {
		ret = db->fd;
		goto err_open;
	}

	db->cache = db_cache_create(db, 4096);
	if (!db->cache) {
		ret = -ENOMEM;
		goto err_cache;
	}

	return 0;

err_cache:
	close(db->fd);
err_open:
	return ret;
}

int db_close(db_t *db, u_int32_t flags)
{
}

static int cache_grow(db_cache_t *cache)
{
	return 0;
}

int db_put(db_t *db, db_txn_t *txnid, dbt_t *key, dbt_t *data, u_int32_t flags)
{
	db_hdr_t *hdr;
	db_cache_t *cache;
	db_block_t *blk;
	char *buf;

	if (!db || !db->db_hdr || !db->cache || !db->blk)
		return -EINVAL;

	hdr   = db->db_hdr;
	cache = db->cache;
	blk   = db->blk;

	while (data->size > cache->free_size)
		cache_grow(cache);

	buf = cache->mem + blk->last_record * hdr->record_size;

	db_mutex_lock(db);
	memcpy(buf, data->data, data->size);

	cache->free_size -= data->size;
	blk->last_record++;
	blk->record_count++;
	db_mutex_unlock(db);
	return 0;
}

int db_get()
{
}

int db_del()
{
}
